package com.gadgets.cm05.statistic;

import org.apache.commons.math3.distribution.ChiSquaredDistribution;
import org.apache.commons.math3.distribution.FDistribution;
import org.apache.commons.math3.distribution.NormalDistribution;
import org.apache.commons.math3.distribution.TDistribution;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 功能说明：统计分布
 * 著作者：修峻青
 * 创建日期：2023-01-07
 */
public class DistributeUtils {

    private static final Logger logger = LoggerFactory.getLogger(DistributeUtils.class);
    /**
     * 正态分布缓存容器
     */
    private static ConcurrentHashMap<String,NormalDistribution> NORMAL_DISTRIBUTE = new ConcurrentHashMap<>();
    /**
     * T 分布缓存容器
     */
    private static ConcurrentHashMap<String,TDistribution> T_DISTRIBUTE = new ConcurrentHashMap<>();
    /**
     * F 分布缓存容器
     */
    private static ConcurrentHashMap<String,FDistribution> F_DISTRIBUTE = new ConcurrentHashMap<>();
    /**
     * 卡方 分布缓存容器
     */
    private static ConcurrentHashMap<String,ChiSquaredDistribution> CHI_DISTRIBUTE = new ConcurrentHashMap<>();

    /**
     * 获取指定的正态分布
     * @param mean          平均值
     * @param variance      方差
     * @return              正态分布对象
     */
    public static NormalDistribution getNormalDistrubute(BigDecimal mean, BigDecimal variance){
        logger.info(
                "开始初始化 N({},{}) 的正态分布",
                mean.setScale(10, RoundingMode.HALF_UP).doubleValue(),
                variance.setScale(10, RoundingMode.HALF_UP).doubleValue()
        );
        String key = mean.setScale(10, RoundingMode.HALF_UP).toPlainString()+","+variance.setScale(10, RoundingMode.HALF_UP).toPlainString();
        synchronized (NORMAL_DISTRIBUTE) {
            if (NORMAL_DISTRIBUTE.containsKey(key)) {
                return NORMAL_DISTRIBUTE.get(key);
            } else {
                NormalDistribution distribution = new NormalDistribution(mean.doubleValue(), variance.doubleValue());
                NORMAL_DISTRIBUTE.put(key, distribution);
                return distribution;
            }
        }
    }

    /**
     * 获取指定的 t 分布
     * @param randomNum     自由度
     * @return              正态分布对象
     */
    public static TDistribution getTDistrubute(BigDecimal randomNum){
        logger.info("开始初始化 t({}) 的分布",randomNum.intValue());
        String key = randomNum.intValue()+"";
        synchronized (T_DISTRIBUTE) {
            if (T_DISTRIBUTE.containsKey(key)) {
                return T_DISTRIBUTE.get(key);
            } else {
                TDistribution distribution = new TDistribution(randomNum.doubleValue());
                T_DISTRIBUTE.put(key, distribution);
                return distribution;
            }
        }
    }

    /**
     * 获取指定的 f 分布
     * @param randomNum1    变量1的自由度
     * @param randomNum2    变量2的自由度
     * @return              正态分布对象
     */
    public static FDistribution getFDistrubute(BigDecimal randomNum1, BigDecimal randomNum2){
        logger.info("开始初始化 F({},{}) 的分布",randomNum1.intValue(),randomNum2.intValue());
        String key = randomNum1.intValue()+","+randomNum2.intValue();
        synchronized (F_DISTRIBUTE) {
            if (F_DISTRIBUTE.containsKey(key)) {
                return F_DISTRIBUTE.get(key);
            } else {
                FDistribution distribution = new FDistribution(randomNum1.doubleValue(), randomNum2.doubleValue());
                F_DISTRIBUTE.put(key, distribution);
                return distribution;
            }
        }
    }

    /**
     * 获取指定的 卡方 分布
     * @param randomNum     变量的自由度
     * @return              正态分布对象
     */
    public static ChiSquaredDistribution getChiquarDistrubute(BigDecimal randomNum){
        logger.info("开始初始化 ChiSquared({},{}) 的分布",randomNum.intValue());
        String key = randomNum.intValue()+"";
        synchronized (CHI_DISTRIBUTE) {
            if (CHI_DISTRIBUTE.containsKey(key)) {
                return CHI_DISTRIBUTE.get(key);
            } else {
                ChiSquaredDistribution distribution = new ChiSquaredDistribution(randomNum.doubleValue());
                CHI_DISTRIBUTE.put(key, distribution);
                return distribution;
            }
        }
    }

    /**
     * 获取标准正态分布（1,0）
     * @return  标准正态分布
     */
    public static NormalDistribution getStandardNormalDistrubute(){
        return getNormalDistrubute(BigDecimal.ZERO, BigDecimal.ONE);
    }

}
